/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package chat.server;

import chat.common.*;
import java.lang.*;
import java.net.*;
import java.io.*;
import java.util.*;

/**
 * Communication Manager, for users and channel
 * @author berthise
 */
public class CommunicationsManager extends Thread {

    private static HashSet<Communication> vectConnection = new HashSet();
    private static HashSet<Channel> vectChannel = new HashSet();
    private boolean alive;
    private ServerSocket socketEcoute;
    private int port;

    public CommunicationsManager(int port) {
        System.out.println("Connection created !");
        alive = true;
        this.port = port;
    }

    public void run() {
        // TODO code application logic here
        try {
            socketEcoute = new ServerSocket(port); // creatin du socket d'ecoute
            while (alive) {
                Socket socketTransfert = socketEcoute.accept(); // accepter la connexion d'un client
                Communication communication = new Communication(this, socketTransfert); // creation du thread du client
                /**
                 * on prepare le message, si l'id est deja utilise, alors on revois une erreur
                 * sinon, c'est ok
                 */
                Message mess = new Message();

                // on lis le message pour recuperer le login
                mess.readMessage(communication.getEntree());
                if (!idExist(mess.getSrc())) { // si le login n'est pas present dans la base, c'est ok
                    communication.start(); // demrage du thread
                    communication.setIdConnection(mess.getSrc());
                    // on previent les autres clients
                    notifyAllClient(mess.getSrc(), Message.CONNECTION_CLIENT);
                    mess = new Message(Message.ACK_CONNECTION, "server", "systemPanel"); //, "connection OK"
                    mess.sendMessage(communication.getSortie());
                    // on envois la list des client au nouveau client
                    notifyClientList(communication);
                    vectConnection.add(communication); // ajout dans un vecteur de connecte
                } else {
                    mess = new Message(Message.ERROR_CONNECTION, "server", "systemPanel"); //, "Login " + mess.getMessageStr() + " is already used !"
                    mess.sendMessage(communication.getSortie());
                    communication.getEntree().close();
                    communication.getSortie().close();
                    communication.getSocket().close();
                    communication = null;
                }
                Thread.sleep(2000);
            }
            socketEcoute.close();
        } catch (Exception e) {
            System.out.println("error test " + e.toString());
        }
    }

    public void closeConnections() {
        try {
            for (Communication connect : vectConnection) {
                try {
                    connect.closeCommunication();
                } catch (Exception e) {
                    System.out.println("error closeclient" + e.toString());
                }
            }
            alive = false;
            System.out.println("Close connection !");
        } catch (Exception e) {
            System.out.println("error fin connection " + e.toString());
        }
    }

    /*
     * fermeture de la connection sur le serveur d'un client
     * On le recherche dans le vecteur de connection
     * puis on ... fin
     * Affichage des information sur le serveur
     */
    public void closeCommunication(String idClient) {
        Communication connectToRemove = null;
        for (Channel channel : vectChannel) {
            if (channel.getVectClient().contains(idClient)) {
                channel.removeClient(idClient);
            }
            if (channel.isEmpty()) {
                vectChannel.remove(channel);
                notifyAllClient(channel.getName(), Message.NOTIFY_RM_CHANNEL);
            }
        }
        for (Communication connect : vectConnection) {
            if (idClient.equalsIgnoreCase(connect.getIdConnection())) {
                try {
                    connect.closeCommunication();
                } catch (Exception ex) {
                }
                connectToRemove = connect;
            }
        }
        if ((connectToRemove != null) && (vectConnection.remove(connectToRemove))) {
            notifyAllClient(idClient, Message.DECONNECTION_CLIENT);
            // prevenir les channels
            // displayInfo();
        }
    }

    public void redirectionMessage(Message mess) {
        if (idExist(mess.getDest())) { // c'est un client
            try {
                mess.sendMessage(getCommunication(mess.getDest()).getSortie());
            } catch (Exception e) {
                System.out.println("error redirection mess " + e.toString());
            }
        } else {
            getChannel(mess.getDest()).sendMessage(mess);
        }
    }

    private void notifyClientList(Communication com) {
        String list = new String();
        if (!vectConnection.isEmpty()) {
            for (Communication connect : vectConnection) {
                list += connect.getIdConnection() + ";";
            }
        }
        String list_channel = new String();
        if (!vectChannel.isEmpty()) {
            for (Channel channel : vectChannel) {
                list_channel += channel.getName() + ";";
            }
        }
        Message mess = new Message(Message.LIST, "server", com.getIdConnection(), "CLIENT;" + list + "-CHANNEL;" + list_channel + "-");
        try {
            mess.sendMessage(com.getSortie());
        } catch (Exception e) {
            System.out.println("error closeclient" + e.toString());
        }
    }

    private void notifyAllClient(String id, int typeMessage) {
        Message mess = new Message(typeMessage, "server", "", id);
        for (Communication connect : vectConnection) {
            mess.setDest(connect.getIdConnection());
            try {
                mess.sendMessage(connect.getSortie());
            } catch (Exception e) {
                System.out.println("error closeclient" + e.toString());
            }
        }
    }

    public void channelManager(Message mess, Communication com) {
        if (mess.getType() == Message.ADD_CHANNEL && !idExistChannel(mess.getMessageStr())) {
            Channel ch = new Channel(mess.getMessageStr(), this);
            vectChannel.add(ch);
            notifyAllClient(ch.getName(), Message.NOTIFY_ADD_CHANNEL);
        } else if (mess.getType() == Message.NEW_CLIENT_CHANNEL) {
            getChannel(mess.getDest()).addClient(com.getIdConnection());
        } else if (mess.getType() == Message.RM_CLIENT_CHANNEL) {
            System.out.println("test : " + mess.getDest());
            if (getChannel(mess.getDest()) != null) {
                getChannel(mess.getDest()).removeClient(com.getIdConnection());
            }
            if (getChannel(mess.getDest()).isEmpty()) {
                vectChannel.remove(getChannel(mess.getDest()));
                notifyAllClient(mess.getDest(), Message.NOTIFY_RM_CHANNEL);
            }
        } else { // channel existe !
            mess = new Message(Message.TEXT, "server", com.getIdConnection(), "Channel \"" + mess.getMessageStr() + "\" already exist !");
            try {
                mess.sendMessage(com.getSortie());
            } catch (Exception e) {
                System.out.println("error closeclient" + e.toString());
            }
        }
    }


    /*
     * quelque information sur le serveur
     */
    public void displayInfo() {
        System.out.println("-------------------------------");
        System.out.println("CLIENT");
        System.out.println("-------------------------------");
        for (Communication connect : vectConnection) {
            System.out.println("nom client: " + connect.getIdConnection());
        }
        System.out.println("nb client connecter : " + vectConnection.size());
        System.out.println("-------------------------------");
        System.out.println("CHANNEL");
        System.out.println("-------------------------------");
        for (Channel channel : vectChannel) {
            System.out.println("nom channel: " + channel.getName());
        }
        System.out.println("nb channel : " + vectChannel.size());
        System.out.println("-----------FIN----------------");
    }

    /*
     * revois vrai si une connection a deja l'identifiant id
     */
    private boolean idExist(String id) {
        boolean b = false;
        for (Communication connect : vectConnection) {
            if (id.equalsIgnoreCase(connect.getIdConnection())) {
                b = true;
            }
        }
        return b;
    }

    private boolean idExistChannel(String id) {
        boolean b = false;
        for (Channel channel : vectChannel) {
            if (id.equalsIgnoreCase(channel.getName())) {
                b = true;
            }
        }
        return b;
    }

    public Communication getCommunication(String id) {
        Communication b = null;
        for (Communication connect : vectConnection) {
            if (id.equalsIgnoreCase(connect.getIdConnection())) {
                b = connect;
            }
        }
        return b;
    }

    public Channel getChannel(String id) {
        Channel b = null;
        for (Channel channel : vectChannel) {
            if (id.equalsIgnoreCase(channel.getName())) {
                b = channel;
            }
        }
        return b;
    }

    public boolean getAlive() {
        return alive;
    }
}
